/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package jigdo.utils;

import java.io.*;
import java.util.*;

/**
 * INI File parsing utility.
 * This versions supports searching for keys in a case insensitive manner.
 * It also retains the keys original case as well.
 * @author John R Sohn
 */
public class SimpleIniParser {

    /**
     * Represents a single file option key=value
     */
    public class Option implements Comparable {

        public boolean equals(Object o) {
            return this.Name.equals(((Option) o).Name);
        }

        public int compareTo(Object o) {
            return this.Name.compareTo(((Option) o).Name);
        }
        
        /**
         * Key of the keyvalue pair
         */
        public String Name;
  
        /**
         * The value of the key value pair.
         */
        public String Value;

        public Option(String name, String value) {
            Name = name;
            Value = value;
        }
    }

    /**
     * Represents a [section] block and all the options it contains.
     */
    public class IniSection implements Comparable {

        /**
         * Section name.
         */
        public String Name;
        
        /**
         * The key/value pairs.
         */
        public List<Option> Options;

        public boolean equals(Object o) {
            return this.Name.equals(((IniSection) o).Name);
        }

        public int compareTo(Object o) {
            return Name.compareTo(((IniSection) o).Name);
        }

        public IniSection(String SectionName) {
            Name = SectionName;
            Options = new java.util.ArrayList<Option>();
        }

        /**
         * Adds a new Option value to the collection.
         * @param Name
         * @param Value 
         */
        public void Put(String Name, String Value) {
            Options.add(new Option(Name, Value));
            java.util.Collections.sort(Options);
        }

        /**
         * Performs a case insensitive search for an option.
         * @param Name The option name.
         * @return The matched option.
         */
        public Option GetOption(String Name) {
            Iterator i = Options.iterator();

            while (i.hasNext()) {
                Option curr = (Option) i.next();
                if (curr.Name.toLowerCase().equals(Name.toLowerCase())) {
                    return curr;
                }
            }

            return null;

        }
    }
    
    /**
     * The sections contained in this file.
     */
    public List<IniSection> Sections;

    
    /**
     * Internal helper method which tests for a section declaration.
     * @param aline
     * @return 
     */
    private boolean IsSection(String aline) {
        return (aline.startsWith("[") && aline.endsWith("]"));
    }

    /**
     * Internal helper method which extracts a section's name.
     * @param line
     * @return 
     */
    private String extractSection(String line) {
        return line.replace("[", "").replace("]", "");
    }

    
    public SimpleIniParser(InputStream src) throws IOException, java.io.StreamCorruptedException {

        Sections = new ArrayList<IniSection>();

        java.io.InputStreamReader reader = new InputStreamReader(src);
        java.io.BufferedReader file = new BufferedReader(reader);

        String line = file.readLine();
        String CurrSect = null;

        IniSection workingSect = null;

        while (line != null) {
            line = line.trim();

            while (CurrSect == null && line != null) {
                if (this.IsSection(line)) {
                    CurrSect = this.extractSection(line);
                    workingSect = new IniSection(CurrSect);
                    Sections.add(workingSect);
                } else {
                    line = file.readLine();
                }

            }

            if (CurrSect == null) {
                throw new java.io.StreamCorruptedException("No Initial Section Found");
            }

            if (this.IsSection(line)) {
                CurrSect = this.extractSection(line);
                workingSect = new IniSection(CurrSect);
                Sections.add(workingSect);
                Collections.sort(Sections);
            } else if (!line.startsWith("#") && line.indexOf("=") > 0) {
                String[] opt = line.split("=");
                workingSect.Put(opt[0], opt.length > 1 ? opt[1] : "");

            }

            line = file.readLine();
        }

    }

    public IniSection GetSectionNoCase(String section) {

        Iterator i = Sections.iterator();

        while (i.hasNext()) {
            IniSection val = (IniSection) i.next();

            if (val.Name.toLowerCase().equals(section.toLowerCase())) {
                return val;
            }

        }

        return null;
    }

    public String GetOption(String section, String option) {
        IniSection sect = this.GetSectionNoCase(section);
        if (sect == null) {
            return "";
        }

        Option opt = sect.GetOption(option);

        if (opt == null) {
            return "";
        }
        return opt.Value;
    }
}
